package xin.petstore.framework.file.hash;

import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.LinkedList;
import java.util.List;

public class StreamHashCalc extends HashCalc {
    private final InputStream inputStream;
    private final MessageDigest[] messageDigests;
    private long readLength;
    private long readCount;
    private int bufferSize = 1048576;
    private byte[][] byteArrayHash;
    private List<HashProgressInterceptor> ltcps = new LinkedList();

    public StreamHashCalc(InputStream inputStream, String[] algorithms) throws NoSuchAlgorithmException {
        this.inputStream = inputStream;
        this.messageDigests = new MessageDigest[algorithms.length];
        for (int i = 0; i < algorithms.length; i++) {
            this.messageDigests[i] = MessageDigest.getInstance(algorithms[i]);
        }
    }

    @Override
    public long getReadLength() {
        return this.readLength;
    }

    @Override
    public void setReadLength(long len) {
        this.readLength = len;
    }

    @Override
    public long getReadCount() {
        return this.readCount;
    }

    @Override
    public int getBufferSize() {
        return this.bufferSize;
    }

    @Override
    public void setBufferSize(int bufferSize) {
        this.bufferSize = bufferSize;
    }

    public InputStream getInputStream() {
        return this.inputStream;
    }

    @Override
    public Object getSource() {
        return getInputStream();
    }

    @Override
    public MessageDigest[] getMessageDigests() {
        return this.messageDigests;
    }

    @Override
    public byte[][] getByteArrayHash() throws IOException {
        if (this.byteArrayHash == null) {
            updateHash();
        }
        return (byte[][]) this.byteArrayHash.clone();
    }

    @Override
    public String[] getHexStringHash() throws IOException {
        byte[][] byteArrayHash = getByteArrayHash();
        String[] ret = new String[byteArrayHash.length];
        for (int i = 0; i < byteArrayHash.length; i++) {
            ret[i] = bufferToHex(byteArrayHash[i]);
        }
        return ret;
    }

    @Override
    public void addHashProgressInterceptor(HashProgressInterceptor itcp) {
        this.ltcps.add(itcp);
    }

    @Override
    public void removeHashProgressInterceptor(HashProgressInterceptor itcp) {
        this.ltcps.remove(itcp);
    }

    private void updateHash() throws IOException {
        boolean readToEnd = this.readLength == 0L;
        byte[] bytesBuf = new byte[this.bufferSize];
        int readLen;
        while (((readToEnd) || (this.readCount < this.readLength)) &&
                ((readLen = this.inputStream.read(bytesBuf)) > 0)) {
            this.readCount += readLen;
            HashBuffer buf = new HashBuffer(bytesBuf, readLen);
            for (HashProgressInterceptor itcp : this.ltcps) {
                itcp.bytesRead(buf, this);
            }
            if (!buf.isSkip()) {
                for (MessageDigest md : this.messageDigests) {
                    md.update(buf.getData(), buf.getOffset(), buf.getLength());
                }
            }
        }
        this.byteArrayHash = new byte[this.messageDigests.length][];
        for (int i = 0; i < this.messageDigests.length; i++) {
            this.byteArrayHash[i] = this.messageDigests[i].digest();
        }
    }
}

